/**
 * Copyright 2025 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

locals {
  _name = "${local.prefix}${lower(var.name)}"
  ctx = {
    for k, v in var.context : k => {
      for kk, vv in v : "${local.ctx_p}${k}:${kk}" => vv
    } if k != "condition_vars"
  }
  ctx_kms_keys = merge(local.ctx.kms_keys, {
    for k, v in google_kms_key_handle.default : "$kms_keys:autokeys/${k}" => v.kms_key
  })
  ctx_p    = "$"
  location = try(local.ctx.locations[var.location], var.location)
  prefix   = var.prefix == null ? "" : "${var.prefix}-"
  project_id = var.project_id == null ? null : lookup(
    local.ctx.project_ids, var.project_id, var.project_id
  )
  notification = try(var.notification_config.enabled, false)
  topic_create = try(var.notification_config.create_topic.create, null) == true
  bucket = (
    var.bucket_create ? {
      name = try(google_storage_bucket.bucket[0].name, null)
      id   = try(google_storage_bucket.bucket[0].id, null)
      url  = try(google_storage_bucket.bucket[0].url, null)
    }
    : {
      name = local._name
      id   = local._name
      url  = "gs://${local._name}"
    }
  )
}

resource "google_kms_key_handle" "default" {
  for_each = var.kms_autokeys
  project  = local.project_id
  name     = each.key
  location = coalesce(
    try(local.ctx.locations[each.value.location], null),
    each.value.location,
    local.location
  )
  resource_type_selector = each.value.resource_type_selector
}

resource "google_storage_bucket" "bucket" {
  count                       = var.bucket_create ? 1 : 0
  name                        = local._name
  project                     = local.project_id
  location                    = local.location
  storage_class               = var.storage_class
  force_destroy               = var.force_destroy
  uniform_bucket_level_access = var.uniform_bucket_level_access
  labels                      = var.labels
  default_event_based_hold    = var.default_event_based_hold
  enable_object_retention     = var.enable_object_retention
  requester_pays              = var.requester_pays
  public_access_prevention    = var.public_access_prevention
  rpo                         = var.rpo

  dynamic "versioning" {
    for_each = var.versioning == null ? [] : [""]
    content {
      enabled = var.versioning
    }
  }

  dynamic "autoclass" {
    for_each = var.autoclass == null ? [] : [""]
    content {
      enabled = var.autoclass
    }
  }

  dynamic "cors" {
    for_each = var.cors == null ? [] : [""]
    content {
      origin          = var.cors.origin
      method          = var.cors.method
      response_header = var.cors.response_header
      max_age_seconds = max(3600, var.cors.max_age_seconds)
    }
  }

  dynamic "custom_placement_config" {
    for_each = var.custom_placement_config == null ? [] : [""]
    content {
      data_locations = var.custom_placement_config
    }
  }

  dynamic "encryption" {
    for_each = var.encryption_key == null ? [] : [""]
    content {
      default_kms_key_name = lookup(
        local.ctx_kms_keys,
        var.encryption_key,
        var.encryption_key
      )
    }
  }

  dynamic "hierarchical_namespace" {
    for_each = var.enable_hierarchical_namespace == null ? [] : [""]
    content {
      enabled = var.enable_hierarchical_namespace
    }
  }

  dynamic "logging" {
    for_each = var.logging_config == null ? [] : [""]
    content {
      log_bucket        = var.logging_config.log_bucket
      log_object_prefix = var.logging_config.log_object_prefix
    }
  }

  dynamic "lifecycle_rule" {
    for_each = var.lifecycle_rules
    iterator = rule
    content {
      action {
        type          = rule.value.action.type
        storage_class = rule.value.action.storage_class
      }
      condition {
        age                        = rule.value.condition.age
        created_before             = rule.value.condition.created_before
        custom_time_before         = rule.value.condition.custom_time_before
        days_since_custom_time     = rule.value.condition.days_since_custom_time
        days_since_noncurrent_time = rule.value.condition.days_since_noncurrent_time
        matches_prefix             = rule.value.condition.matches_prefix
        matches_storage_class      = rule.value.condition.matches_storage_class
        matches_suffix             = rule.value.condition.matches_suffix
        noncurrent_time_before     = rule.value.condition.noncurrent_time_before
        num_newer_versions         = rule.value.condition.num_newer_versions
        with_state                 = rule.value.condition.with_state
      }
    }
  }

  dynamic "retention_policy" {
    for_each = var.retention_policy == null ? [] : [""]
    content {
      retention_period = var.retention_policy.retention_period
      is_locked        = var.retention_policy.is_locked
    }
  }

  dynamic "soft_delete_policy" {
    for_each = var.soft_delete_retention == null ? [] : [""]
    content {
      retention_duration_seconds = var.soft_delete_retention
    }
  }

  dynamic "website" {
    for_each = var.website == null ? [] : [""]

    content {
      main_page_suffix = var.website.main_page_suffix
      not_found_page   = var.website.not_found_page
    }
  }

  dynamic "ip_filter" {
    for_each = var.ip_filter == null ? [] : [""]
    content {
      mode                           = "Enabled"
      allow_cross_org_vpcs           = var.ip_filter.allow_cross_org_vpcs
      allow_all_service_agent_access = var.ip_filter.allow_all_service_agent_access
      dynamic "public_network_source" {
        for_each = var.ip_filter.public_network_sources == null ? [] : [""]
        content {
          allowed_ip_cidr_ranges = var.ip_filter.public_network_sources
        }
      }
      dynamic "vpc_network_sources" {
        for_each = var.ip_filter.vpc_network_sources
        content {
          network                = vpc_network_sources.key
          allowed_ip_cidr_ranges = vpc_network_sources.value
        }
      }
    }
  }
}

resource "google_storage_bucket_object" "objects" {
  for_each            = var.objects_to_upload
  bucket              = local.bucket.id
  name                = each.value.name
  metadata            = each.value.metadata
  content             = each.value.content
  source              = each.value.source
  cache_control       = each.value.cache_control
  content_disposition = each.value.content_disposition
  content_encoding    = each.value.content_encoding
  content_language    = each.value.content_language
  content_type        = each.value.content_type
  event_based_hold    = each.value.event_based_hold
  temporary_hold      = each.value.temporary_hold
  detect_md5hash      = each.value.detect_md5hash
  storage_class       = each.value.storage_class
  kms_key_name = try(
    local.ctx_kms_keys[each.value.kms_key_name],
    each.value.kms_key_name
  )
  dynamic "customer_encryption" {
    for_each = each.value.customer_encryption == null ? [] : [""]
    content {
      encryption_algorithm = each.value.customer_encryption.encryption_algorithm
      encryption_key       = each.value.customer_encryption.encryption_key
    }
  }
}

resource "google_storage_notification" "notification" {
  count          = local.notification ? 1 : 0
  bucket         = local.bucket.name
  payload_format = var.notification_config.payload_format
  topic = try(
    google_pubsub_topic.topic[0].id, var.notification_config.topic_name
  )
  custom_attributes  = var.notification_config.custom_attributes
  event_types        = var.notification_config.event_types
  object_name_prefix = var.notification_config.object_name_prefix
  depends_on         = [google_pubsub_topic_iam_binding.binding]
}

resource "google_pubsub_topic_iam_binding" "binding" {
  count   = local.topic_create ? 1 : 0
  topic   = google_pubsub_topic.topic[0].id
  role    = "roles/pubsub.publisher"
  members = ["serviceAccount:${var.notification_config.sa_email}"]
}

resource "google_pubsub_topic" "topic" {
  count        = local.topic_create ? 1 : 0
  project      = local.project_id
  name         = var.notification_config.topic_name
  kms_key_name = try(var.notification_config.topic_create.kms_key_id, null)
}
